﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using UtilZ.Dotnet.Ex.Model;

namespace UtilZ.Dotnet.Ex.Communication.Net.Web
{
    /// <summary>
    /// http请求范围
    /// </summary>
    public class HttpRequestRange
    {
        /*************************************************************
         * rangeStr:0-50,100-150 请求范围用逗号分隔
         * Range: 
         * 0-499				    表示请求从0-499字节(请求数据长度 = end - begin + 1)
         * -500					    表示最后多少字节
         * 500-					    表示跳过开头500字节后的所有
         *************************************************************/

        /// <summary>
        /// 单位
        /// </summary>
        private readonly string _unit;

        /// <summary>
        /// 原始范围字符串
        /// </summary>
        private readonly string _rangeStr;

        /// <summary>
        /// http请求范围类型
        /// </summary>
        private readonly HttpRequestRangeTypes _rangeType;

        /// <summary>
        /// 请求数据位置
        /// </summary>
        private readonly long _beginPostition;

        /// <summary>
        /// 请求数据结束
        /// </summary>
        private readonly long _endPosition;

        /// <summary>
        /// 请求数据长度
        /// </summary>
        private readonly long _length;


        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="unit">单位</param>
        /// <param name="rangeStr">范围段字符串</param>
        public HttpRequestRange(string unit, string rangeStr)
        {
            this._unit = unit;
            this._rangeStr = rangeStr;

            if (rangeStr.StartsWith(WebConstnats.LINEAE_TRANSVERAE))
            {
                //-500 表示最后多少字节
                this._rangeType = HttpRequestRangeTypes.LastBytes;
                this._length = int.Parse(rangeStr.Substring(1));
            }
            else if (rangeStr.EndsWith(WebConstnats.LINEAE_TRANSVERAE))
            {
                //500- 表示跳过开头500字节后的所有
                this._rangeType = HttpRequestRangeTypes.SkipToEnd;
                this._beginPostition = long.Parse(rangeStr.Substring(0, rangeStr.Length - 1));
            }
            else
            {
                //0-499 表示请求从0-499字节(请求数据长度 = end - begin + 1)
                this._rangeType = HttpRequestRangeTypes.Area;
                int index = rangeStr.IndexOf(WebConstnats.LINEAE_TRANSVERAE);
                this._beginPostition = long.Parse(rangeStr.Substring(0, index));
                this._endPosition = long.Parse(rangeStr.Substring(index + 1));
            }
        }


        /// <summary>
        /// 获取内容数据范围
        /// </summary>
        /// <param name="totalLength">数据总大小</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="NotImplementedException"></exception>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        public ContentRangeInfo GetArea(long totalLength)
        {
            if (totalLength < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(totalLength));
            }

            long offset, length, endPostion;
            switch (this._rangeType)
            {
                case HttpRequestRangeTypes.Area:
                    offset = this._beginPostition;
                    length = this._endPosition - this._beginPostition;
                    endPostion = offset + length - 1;
                    break;
                case HttpRequestRangeTypes.SkipToEnd:
                    offset = this._beginPostition;
                    length = totalLength - offset;
                    if (length > WebConstnats.RES_PART_CONTENT_MAX_SIZE)
                    {
                        length = WebConstnats.RES_PART_CONTENT_MAX_SIZE;
                    }
                    endPostion = offset + length - 1;
                    break;
                case HttpRequestRangeTypes.LastBytes:
                    offset = totalLength - this._length - 1;
                    length = this._length;
                    endPostion = offset + length;
                    break;
                default:
                    throw new NotImplementedException(this._rangeType.ToString());
            }

            if (offset < 0 || offset + length > totalLength)
            {
                throw new ArgumentOutOfRangeException(nameof(totalLength), this._rangeStr);
            }

            //bytes 20-50/826           
            //bytes 20-50/*      表示总数据长度未知
            //Content-Range: bytes 0-800/801    注：801文件总大小
            string contentRange = $"{this._unit} {offset}-{endPostion}/{totalLength}";
            return new ContentRangeInfo(contentRange, offset, length);
        }
    }
}
